import sys
import os
from datetime import datetime
from optparse import OptionParser
import urllib
import string
import xlrd
import xlwt
import xlutils.copy
import re
import copy
import types
from BeautifulSoup import BeautifulSoup

class TestPriceParser(object):
    def __init__(self, mainURL):
        self._successor = None
        self._mainURL = mainURL

    def SetSuccessor(self, successor):
        self._successor = successor

    def GetPriceFromLink(self, link):
        price = -1
        if string.find(link, self._mainURL) != -1:
            try:
                f=open(link)
                data=f.read()
                f.close()
            except IOError:
                data=''
            price = self.ParsePrice(data)
        else:
            if self._successor != None:
                return self._successor.GetPriceFromLink(link)

        return price


    def ParsePrice(self,data):
        price = -1
        return price



class PriceParser(object):
    def __init__(self, mainURL):
        self._successor = None
        self._mainURL = mainURL

    def SetSuccessor(self, successor):
        self._successor = successor

    def GetPriceFromLink(self, link):
        price = -1
        if string.find(link, self._mainURL) != -1:
            try:
                data=urllib.urlopen(link).read()
            except IOError:
                data=''
            price = self.ParsePrice(data)
            #price = self._mainURL
        else:
            if self._successor != None:
                return self._successor.GetPriceFromLink(link)

        return price


    def ParsePrice(self,data):
        price = -1
        return price


class PriceParserGymboree(PriceParser):

    def ParsePrice(self,data):
        #create a pattern, replacement function to replace '<>' as ''
        #cause beautifusoup can not parse correctly when the attrs include '<>'
        myMassage = [(re.compile('<>'), lambda match: '')]
        myNewMassage = copy.copy(BeautifulSoup.MARKUP_MASSAGE)
        myNewMassage.extend(myMassage)

        soup=BeautifulSoup(data,markupMassage=myNewMassage)
        content = soup.find("input",attrs={'name':"ADD_CART_ITEMsalePriceAmt"})
        if content == None:
            salePrice = -1
        else:
            salePrice = content['value']

        return salePrice

class PriceParserTheNorthFace(PriceParser):
    def ParsePrice(self,data):
        return -1

class PriceParserBackCountry(PriceParser):
    def ParsePrice(self,data):
        price = -1

        soup=BeautifulSoup(data)

        #check out of stock
        content = soup.find("h2",text='Temporarily Out of Stock')
        if content != None:
            #the product is out of stock
            return -1

        #it's in stock , check low price
        content = soup.find("meta", attrs={'itemprop':'lowPrice'})
        if content != None:
            #the product has a low price
            price = content['content']
            #the origianl price has the format $36.80, should delete $
            price = re.match('\$(.*)', price).group(1)
            return price

        #there is no low price, there is no discount
        content = soup.find("meta", attrs={'itemprop':'price'})
        if content != None:
            #the product has price
            price = content['content']
            #the origianl price has the format $36.80, should delete $
            price = re.match('\$(.*)', price).groups()[0]
            return price

        return -1

class PriceParser6pm(TestPriceParser):
    def ParsePrice(self, data):
        price = -1
        content = ''
        info={}

        soup = BeautifulSoup(data)
        #content = soup.prettify()
        #l = soup.findAll('a', href=re.compile('/ralph-lauren-layette-kids.*'))
        try:
            l = soup.find('span', attrs={'id':'price'})
            if l==None:
                price="$0"
            else:
                price = l.contents[0]
        except:
            price="$0"


        try:
            priceValue=re.match(r"\n.*\$(.*)\n", price).groups()[0]
        except:
            try:
                priceValue=re.match(r".*\$(.*)", price).groups()[0]
            except:
                priceValue=0

        return priceValue






##################################################################################
#when need add web store , create a parser for this web ,then add the parser here
def InitParserList():
    lParser = []
    #add gymboree parser
    lParser.append(PriceParserGymboree('www.gymboree.com'))
    lParser.append(PriceParserTheNorthFace('www.thenorthface.com'))
    lParser.append(PriceParserBackCountry('www.backcountry.com'))
    lParser.append(PriceParser6pm(r'D:\Work'))

    return lParser
##################################################################################

class TrackPrice():
    def __init__(self):
        #init the parser responsibility chain using the parser list
        self.parser = self.InitChain(InitParserList())
        self.price = {}

    def InitChain(self, parserList):
        length = len(parserList)
        #there is no any parser
        if length == 0:
            return None

        #has at least one parser
        for i in range(length-1):
            parserList[i].SetSuccessor(parserList[i+1])

        #return the first one
        return parserList[0]

    def GetStyle(self,level):
        if level=='warn':
            style = xlwt.easyxf('font: name Times New Roman, colour_index blue, bold on;\
                    pattern: back_colour red, pattern solid, fore-colour red')
        elif level=='fata':
            style = xlwt.easyxf('font: name Times New Roman, colour_index yellow, bold on;\
                    pattern: back_colour red, pattern solid, fore-colour black')
        elif level=='info':
            style = xlwt.easyxf('font: name Times New Roman, colour_index yellow, bold on;\
                    pattern: back_colour red, pattern solid, fore-colour blue')

        else:
            style = xlwt.easyxf()

        return style


    def updateOne(self, file, row):
        #open the excel file
        excel=xlrd.open_workbook(file)

        #get the product sheet, the product sheet must be the first sheet
        stProduct = excel.sheet_by_index(0)

        #use another copy to write
        wb=xlutils.copy.copy(excel)
        ws=wb.get_sheet(0)

        if self.parser != None:
                #get the product ID and link address
            pid = stProduct.row(row)[0].value
            link = stProduct.row(row)[2].value
            prePrice = stProduct.row(row)[3].value
            record = stProduct.row(row)[4].value

            if (not type(link) is types.StringType) and (not type(link) is types.UnicodeType):
                link = ''
            price = self.parser.GetPriceFromLink(link)
            price = string.atof(price)

            level='normal'
            if price != prePrice:
                level='info'
            if price == 0:
                level='fata'
            if price > record:
                level='warn'

            ws.write(i,3,price,self.GetStyle(level))

        wb.save(file)

    def StartTrack(self, file, options):

        line=options.line

        #open the excel file
        excel=xlrd.open_workbook(file)

        #get the product sheet, the product sheet must be the first sheet
        stProduct = excel.sheet_by_index(0)

        #use another copy to write
        wb=xlutils.copy.copy(excel)
        ws=wb.get_sheet(0)

        #get the line range:
        if string.upper(line) == 'ALL':
            low=1
            high=stProduct.nrows
        else:
            try:
                m=re.match('(\d+):(\d+)', line)
                low = string.atoi(m.groups()[0])
                high = string.atoi(m.groups()[1])
            except:
                try:
                    m=re.match('(\d+)', line)
                    low = string.atoi(m.groups()[0])
                    high = string.atoi(m.groups()[0]) + 1
                except:
                    low=1
                    high=stProduct.nrows

        if low == 0:
            low = 1

        if high>stProduct.nrows:
            high=stProduct.nrows


        if self.parser != None:
            for i in range(1,stProduct.nrows):
                #get the product ID and link address
                pid = stProduct.row(i)[0].value
                link = stProduct.row(i)[2].value
                prePrice = stProduct.row(i)[3].value
                record = stProduct.row(i)[4].value

                if (not type(link) is types.StringType) and (not type(link) is types.UnicodeType):
                    link = ''

                if i in range(low, high):
                    #this range shoud be update
                    price = self.parser.GetPriceFromLink(link)
                    price = string.atof(price)
                else:
                    price=prePrice

                level='normal'
                if price != prePrice:
                    level='info'
                if price == 0:
                    level='fata'
                if price > record:
                    level='warn'

                ws.write(i,3,price,self.GetStyle(level))

            now=datetime.now()
            name = "%02d%02d%02d_%s" % (now.year,now.month,now.day, os.path.basename(file))

            wb.save(name)

if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option("-u", "--update", dest="line",
                  help="update the price", default='All')

    (options, args) = parser.parse_args()

    tracker = TrackPrice()
    tracker.StartTrack(sys.argv[1], options)



